/* eslint-disable no-param-reassign */
const Joi = require('joi');
const { ApiError } = require('../utils/errorHandler');

/**
 * Helper function to pick specific properties from an object
 */
const pick = (object, keys) => keys.reduce((obj, key) => {
  if (object && Object.prototype.hasOwnProperty.call(object, key)) {
    obj[key] = object[key];
  }
  return obj;
}, {});

/**
 * Validation middleware factory
 * @param {Object} schema - Joi validation schema
 */
const validate = (schema) => (req, res, next) => {
  const validSchema = pick(schema, ['params', 'query', 'body']);
  const object = pick(req, Object.keys(validSchema));
  const { value, error } = Joi.compile(validSchema)
    .prefs({ errors: { label: 'key' }, abortEarly: false })
    .validate(object);

  if (error) {
    const errorMessage = error.details
      .map((details) => details.message)
      .join(', ');
    return next(new ApiError(400, errorMessage));
  }

  // Replace request data with validated data
  Object.assign(req, value);
  return next();
};

/**
 * Create validation schemas for config routes
 */
const configValidation = {
  createConfig: {
    body: Joi.object().keys({
      name: Joi.string().required().max(100),
      description: Joi.string().max(500),
      config: Joi.object().required().min(1),
    }),
  },
  updateConfig: {
    params: Joi.object().keys({
      id: Joi.string().required().regex(/^[0-9a-fA-F]{24}$/),
    }),
    body: Joi.object().keys({
      name: Joi.string().max(100),
      description: Joi.string().max(500),
      config: Joi.object().min(1),
    }).min(1),
  },
  getConfig: {
    params: Joi.object().keys({
      id: Joi.string().required().regex(/^[0-9a-fA-F]{24}$/),
    }),
  },
  deleteConfig: {
    params: Joi.object().keys({
      id: Joi.string().required().regex(/^[0-9a-fA-F]{24}$/),
    }),
  },
  getConfigs: {
    query: Joi.object().keys({
      page: Joi.number().integer().min(1).default(1),
      limit: Joi.number().integer().min(1).max(100)
        .default(10),
      sortBy: Joi.string().valid('name', 'createdAt', 'updatedAt').default('createdAt'),
      order: Joi.string().valid('asc', 'desc').default('desc'),
    }),
  },
  searchConfigs: {
    query: Joi.object().keys({
      q: Joi.string().allow(''),
      page: Joi.number().integer().min(1).default(1),
      limit: Joi.number().integer().min(1).max(100)
        .default(10),
      sortBy: Joi.string().valid('name', 'createdAt', 'updatedAt').default('createdAt'),
      order: Joi.string().valid('asc', 'desc').default('desc'),
    }),
  },
};

module.exports = {
  validate,
  configValidation,
};
